#ifndef _SGF_ARRAY_H_
#define _SGF_ARRAY_H_

#include "Type.h"

namespace SGF
{
	template <class T>
	class Array
	{
	private:
		T* _elements;
		UInt64 _size;
	public:
		Array();
		Array(UInt64 size);
		Array(const Array<T>& src);
		Array<T>& operator=(const Array<T>& src);
		~Array();
		T& operator[](UInt64 i);
		void Add(T src);
		void Insert(UInt64 pos, T src);
		void Remove(T src);
		void RemoveIndex(UInt64 pos);
		void Clear();
		void SetSize(UInt64 size);
		UInt64	GetSize();
	};

	template <class T>
	SGF::Array<T>::Array()
	{
		_elements = NULL;
		_size = 0;
	}

	template <class T>
	SGF::Array<T>::Array(UInt64 size)
	{
		if (size > 0)
		{
			_elements = new T[size];
			_size = size;
		}
		else
		{
			_elements = NULL;
			_size = 0;
		}
	}

	template <class T>
	SGF::Array<T>::Array(const Array<T>& src)
	{
		if (src._size == 0)
		{
			_elements = NULL;
			_size = 0;
		}
		else
		{
			_size = src._size;
			_elements = new T[_size];
			for (UInt64 i = 0; i < _size; i++)
			{
				_elements[i] = src._elements[i];
			}
		}
	}

	template <class T>
	Array<T>& SGF::Array<T>::operator=(const Array<T>& src)
	{
		delete[] _elements;
		if (src._size == 0)
		{
			_elements = NULL;
			_size = 0;
		}
		else
		{
			_size = src._size;
			_elements = new T[_size];
			for (UInt64 i = 0; i < _size; i++)
			{
				_elements[i] = src._elements[i];
			}
		}
		return*this;
	}

	template <class T>
	SGF::Array<T>::~Array()
	{
		if (_size > 0)
		{
			delete[] _elements;
		}
	}

	template <class T>
	T& SGF::Array<T>::operator[](UInt64 i)
	{
		if ((i >= 0) && (i < _size))
		{
			return _elements[i];
		}
		else
		{
			throw 10;
		}
	}

	template <class T>
	void SGF::Array<T>::Add(T src)
	{
		if (_size == 0)
		{
			_size = 1;
			_elements = new T[1];
			_elements[0] = src;
		}
		else
		{
			_size++;
			T* newElements = new T[_size];
			for (UInt64 i = 0; i < _size - 1; i++)
			{
				newElements[i] = _elements[i];
			}
			newElements[_size - 1] = src;
			delete[] _elements;
			_elements = newElements;
		}
	}

	template <class T>
	void SGF::Array<T>::Insert(UInt64 pos, T src)
	{
		if (pos < _size)
		{
			if (pos == _size)
			{
				_size++;
				T* newElements = new T[_size];
				for (UInt64 i = 0; i < _size - 1; i++)
				{
					newElements[i] = _elements[i];
				}
				newElements[_size - 1] = src;
				delete[] _elements;
				_elements = newElements;
			}
			else
			{
				_size++;
				T* newElements = new T[_size];
				for (UInt64 i = 0; i < pos; i++)
				{
					newElements[i] = _elements[i];
				}
				newElements[pos] = src;
				for (UInt64 i = pos + 1; i < _size; i++)
				{
					newElements[i] = _elements[i - 1];
				}
				delete[] _elements;
				_elements = newElements;;
			}
		}
		else
		{
			if ((_size == 0) && (pos == 0))
			{
				_size = 1;
				_elements = new T[1];
				_elements[0] = src;
			}
		}
	}

	template <class T>
	void SGF::Array<T>::Remove(T src)
	{
		if (_size > 0)
		{
			UInt64 pos = 0;
			while ((pos < _size) && (_elements[pos] != src))
			{
				pos++;
			}
			if (pos < _size)
			{
				_size--;
				if (_size == 0)
				{
					delete[] _elements;
					_elements = NULL;
					_size = 0;
				}
				else
				{
					T* newElements = new T[_size];
					for (UInt64 i = 0; i < pos; i++)
					{
						newElements[i] = _elements[i];
					}
					for (UInt64 i = pos; i < _size; i++)
					{
						newElements[i] = _elements[i + 1];
					}
					delete[] _elements;
					_elements = newElements;
				}
			}
		}

	}

	template <class T>
	void SGF::Array<T>::RemoveIndex(UInt64 pos)
	{
		if ((_size > 0) && (pos < _size))
		{
			_size--;
			if (_size == 0)
			{
				delete[] _elements;
				_elements = NULL;
				_size = 0;
			}
			else
			{
				T* newElements = new T[_size];
				for (UInt64 i = 0; i < pos; i++)
				{
					newElements[i] = _elements[i];
				}
				for (UInt64 i = pos; i < _size; i++)
				{
					newElements[i] = _elements[i + 1];
				}
				delete[] _elements;
				_elements = newElements;
			}
		}
	}

	template <class T>
	void SGF::Array<T>::Clear()
	{
		delete[] _elements;
		_elements = NULL;
		_size = 0;
	}

	template <class T>
	UInt64 SGF::Array<T>::GetSize()
	{
		return _size;
	}

	template <class T>
	void SGF::Array<T>::SetSize(UInt64 size)
	{
		if (size == 0)
		{
			delete[] _elements;
			_elements = NULL;
			_size = 0;
			return;
		}
		if (size != _size)
		{
			if (size > _size)
			{
				T*  newElements = new T[size];
				for (UInt64 i = 0; i < _size; i++)
				{
					newElements[i] = _elements[i];
				}
				delete[] _elements;
				_elements = newElements;
			}
			else
			{
				T* newElements = new T[size];
				for (UInt64 i = 0; i < size; i++)
				{
					newElements[i] = _elements[i];
				}
				delete[] _elements;
				_elements = newElements;
			}
			_size = size;
		}
	}

}
#endif

